﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using QuadRemote.Core;

namespace QuadRemote.Panels
{
    class AttitudePanel : QuadPanel
    {
        Bitmap buffer;
        Graphics bufferGraphics;

        public float pitch;
        public float roll;

        public AttitudePanel()
            : base("Attitude",200,200,Color.Blue,50)
        {
            lockAspect = true;
        }

        private float toRadians(double angle)
        {
            return (float)(Math.PI * angle / 180.0);
        }

        public override void PaintPanel(System.Drawing.Graphics g2)
        {
            bool repaint = false;
            if (buffer == null || PanelWidth != buffer.Width || PanelHeight != buffer.Height)
            {
                buffer = new Bitmap(PanelWidth, PanelHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                bufferGraphics = Graphics.FromImage(buffer);
                bufferGraphics.SmoothingMode = SmoothingMode.HighQuality;
                repaint = true;
            }
            Graphics g = bufferGraphics;
            
            Brush b;
            Pen p;
            int fade = 64;
            int fadeText = 128;
            int margin = 2;
            float angStartUpper = 0;
            float angExtUpper = 0;
            float rollAngle = roll;// 0;// RemoteController.instance().latestState.roll;
            float pitchAngle = pitch; // 0; // RemoteController.instance().latestState.pitch;
            if (pitchAngle >= 180) pitchAngle -= 360;
            if (rollAngle >= 180) rollAngle -= 360;
            float radius = (PanelWidth / 2) - margin * 2;
            PointF centerPoint = new PointF(radius, radius);

            Matrix at;

            if (repaint)
            {
                
            }

            
            bool reverse = false;
            at = new Matrix();
            at.RotateAt(rollAngle, new PointF(centerPoint.X+margin,centerPoint.Y+margin));

            at.Translate(margin, margin);
            g.Transform = at;
            

            if ((pitchAngle < 90) && (pitchAngle > -90))
            {
                angStartUpper = -pitchAngle;  // Minus because of the reverse way of working of the artificial horizon positive values let the blue arc to get bigger...
                angExtUpper = (180 - (angStartUpper * 2));
            }

            if ((pitchAngle >= 90) && (pitchAngle < 180))
            {
                at = new Matrix();
                at.RotateAt(180+rollAngle, new PointF(centerPoint.X+margin, centerPoint.Y+margin));
                at.Translate(margin, margin);
                g.Transform = at;
                reverse = true;


                angStartUpper = -(180 - pitchAngle);  // Minus because of the reverse way of working of the artificial horizon positive values let the blue arc to get bigger...
                angExtUpper = (180 - (2 * angStartUpper));
            }

            if ((pitchAngle <= -90) && (pitchAngle > -180))
            {
                at = new Matrix();
                at.RotateAt(180 + rollAngle, new PointF(centerPoint.X+margin, centerPoint.Y+margin));
                at.Translate(margin, margin);
                g.Transform = at;

                angStartUpper = (180 + pitchAngle);  // Minus because of the reverse way of working of the artificial horizon positive values let the blue arc to get bigger...
                angExtUpper = (180 - (2 * angStartUpper));
                reverse = true;
            }

            GraphicsPath clip = new GraphicsPath();
            clip.AddEllipse(margin-1, margin-1, radius * 2, radius * 2);
            g.SetClip(clip);


            Color sky = Color.FromArgb(fade, Color.Blue);
            Color earth = Color.FromArgb(fade, Color.Brown);
            Color darkSky = Color.FromArgb(fade, Color.DarkBlue);
            Color darkEarth = Color.FromArgb(fade, Color.Orange);

            // Draw the artificial horizon itself, composed by 2 half arcs

            GraphicsPath path = new GraphicsPath();
            path.AddArc(0, 0, radius * 2, radius * 2, angStartUpper, -(360 - angExtUpper));

            b = new LinearGradientBrush(new Point(0, 0), new Point(0, PanelHeight), reverse ? darkSky : sky, reverse ? sky : darkSky);
            
            g.FillPath(b, path);
            path = new GraphicsPath();
            path.AddArc(0, 0, radius * 2, radius * 2, angStartUpper, angExtUpper);
            b = new LinearGradientBrush(new Point(0, 0), new Point(0, PanelHeight), reverse ? darkEarth : earth, reverse ? earth : darkEarth);

            p = new Pen(Color.FromArgb(fade, Color.White), 2);
            g.FillPath(b, path);
            PointF begin = path.PathPoints[0];
            PointF end = path.PathPoints[path.PointCount - 1];
            g.DrawLine(p, begin, end);

            //g.FillPie(Brushes.Blue, 0, 0, radius * 2, radius * 2, angStartUpper, -(360 - angExtUpper));
            //g.FillPie(Brushes.Brown, 0, 0, radius * 2, radius * 2, angStartUpper, angExtUpper);

            float angle;
            float distance;
            float angleCorrUp;
            int limitInf, limitMax;

            limitInf = (int)(Math.Round(pitchAngle / 5) - 5);
            if (limitInf < -36) limitInf = -36;
            limitMax = limitInf + 10;
            if (limitMax > 36) limitMax = 37;

            int dimMarker10Deg = (int)(radius / 8);
            int dimMarker5Deg = 5;

            float round = 3;

            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;

            for (int i = limitInf; i < limitMax; i++)
            {

                angle = i * 5;    // Display the text at the right "height"

                angleCorrUp = angle - pitchAngle;
                distance = Math.Abs(angleCorrUp * (float)Math.Sqrt(Math.Abs(angleCorrUp))) / 4;       // Put the text and the lines length at the right position

                if (angle % 10 == 0)
                {
                    p = new Pen(Color.FromArgb(fade, Color.White), 3 - Math.Abs(angleCorrUp / 10));
                    g.DrawLine(p,(int)(centerPoint.X - dimMarker10Deg - distance),
                            (int)(centerPoint.Y - (radius * 0.8 * Math.Sin(toRadians(angleCorrUp) * round)))
                            , (int)(centerPoint.X + dimMarker10Deg + distance),
                            (int)(centerPoint.Y - (radius * 0.8 * Math.Sin(toRadians(angleCorrUp) * round))));

                    // Writing routine

                    //if (angle == 0) continue;

                    //if (Math.Abs(angleCorrUp) < 3) continue;
                    //g2d.setFont(new Font("Calibri",Font.PLAIN,14 - Math.abs((int)(angleCorrUp/4.0))));
                    g.DrawString("" + (int)(angle),
                                new Font("Calibri", radius / 13 * (1 - (float)Math.Abs(angleCorrUp / 50)), FontStyle.Bold),
                                new SolidBrush(Color.FromArgb(fadeText,Color.White)),
                                (float)centerPoint.X - dimMarker10Deg - distance - 20,
                                (float)centerPoint.Y - (radius * 0.8f * (float)Math.Sin(toRadians(angleCorrUp) * round)) + 2.5F,
                                format);
                    
                    
                    /*g.DrawString("" + (int)(angle),
                                new Font("Calibri", radius / 13 * (1 - (float)Math.Abs(angleCorrUp / 50)), FontStyle.Bold),
                                new SolidBrush(Color.FromArgb(fadeText, Color.White)),
                                (float)centerPoint.X + dimMarker10Deg + distance + 20,
                                (float)centerPoint.Y - (radius * 0.8f * (float)Math.Sin(toRadians(angleCorrUp) * round)) + 2.5F,
                                format);*/

                }
                else if (angle % 5 == 0)
                {
                    // Short markers
                    g.DrawLine(new Pen(Color.FromArgb(fade,Color.White)),
                            (int)(centerPoint.X - dimMarker5Deg),
                            (int)(centerPoint.Y - (radius * 0.8 * Math.Sin(toRadians(angleCorrUp) * round))),
                            (int)(centerPoint.X + dimMarker5Deg),
                            (int)(centerPoint.Y - (radius * 0.8 * Math.Sin(toRadians(angleCorrUp) * round))));
                }
            }

            p = new Pen(Color.FromArgb(fade,Color.White), 2);
            g.DrawLine(p, centerPoint.X - radius / 5, centerPoint.Y, centerPoint.X - 15, centerPoint.Y);
            g.DrawLine(p, centerPoint.X - 15, centerPoint.Y, centerPoint.X - 10, centerPoint.Y + 10);
            g.DrawLine(p, centerPoint.X - 10, centerPoint.Y + 10, centerPoint.X, centerPoint.Y);
            g.DrawLine(p, centerPoint.X + 10, centerPoint.Y + 10, centerPoint.X, centerPoint.Y);
            g.DrawLine(p, centerPoint.X + 15, centerPoint.Y, centerPoint.X + 10, centerPoint.Y + 10);
            g.DrawLine(p, centerPoint.X + radius / 5, centerPoint.Y, centerPoint.X + 15, centerPoint.Y);

            /*g.DrawString("" + (int)pitchAngle + "°", new Font("Calibri", 11, FontStyle.Bold), new SolidBrush(Color.FromArgb(fade,Color.Black)), centerPoint.X + radius / 5 + 20, centerPoint.Y, format);
            g.DrawString("" + (int)pitchAngle + "°", new Font("Calibri", 11, FontStyle.Bold), new SolidBrush(Color.FromArgb(fade, Color.Black)), centerPoint.X - radius / 5 - 20, centerPoint.Y, format);
            g.DrawString("" + (int)rollAngle + "°", new Font("Calibri", 11, FontStyle.Bold), new SolidBrush(Color.FromArgb(fadeText, Color.Black)), centerPoint.X, centerPoint.Y - radius + 20, format);*/
            g.DrawString("" + (int)pitchAngle + "°", new Font("Calibri", radius/11, FontStyle.Bold), new SolidBrush(Color.FromArgb(fadeText, Color.White)), centerPoint.X + radius / 5 + 20, centerPoint.Y, format);
            //g.DrawString("" + (int)pitchAngle + "°", new Font("Calibri", radius / 11, FontStyle.Bold), new SolidBrush(Color.FromArgb(fadeText, Color.White)), centerPoint.X - radius / 5 - 20, centerPoint.Y, format);
            g.DrawString("" + (int)rollAngle + "°", new Font("Calibri", radius / 11, FontStyle.Bold), new SolidBrush(Color.FromArgb(fadeText, Color.White)), centerPoint.X, centerPoint.Y - radius * 0.85F, format);


            /*
             * g2d.setFont(writing);

            // Draw the center shape
            GeneralPath centerShape = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
            centerShape.moveTo((centerPoint.getX() - radius / 5), centerPoint.getY());
            centerShape.lineTo((centerPoint.getX() - 15), centerPoint.getY());
            //centerShape.moveTo((centerPoint.getX() - 20), centerPoint.getY());
            centerShape.moveTo((centerPoint.getX() - 10), (centerPoint.getY() + 10));
            centerShape.lineTo(centerPoint.getX(), centerPoint.getY());
            centerShape.lineTo((centerPoint.getX() + 10), (centerPoint.getY() + 10));
            //centerShape.lineTo((centerPoint.getX() + 20), centerPoint.getY());
            centerShape.moveTo((centerPoint.getX() + radius / 5), centerPoint.getY());
            centerShape.lineTo((centerPoint.getX() + 15), centerPoint.getY());

            FontMetrics metrics = g2d.getFontMetrics();

            Rectangle2D rect = metrics.getStringBounds("" + (int)pitchAngle + "°", g2d);

            g2d.drawString("" + (int)pitchAngle + "°",
                            (float)(centerPoint.getX() - rect.getCenterX()),
                            (float)(centerPoint.getY() + rect.getCenterY()));
            rect = metrics.getStringBounds("" + (int)rollAngle + "°", g2d);
            g2d.drawString("" + (int)rollAngle + "°",
                            (float)(centerPoint.getX() - rect.getCenterX()),
                            (float)(centerPoint.getY() - radius + rect.getCenterY()));

            g2d.setPaint(Color.white);
            g2d.setStroke(new BasicStroke(2));
            g2d.draw(centerShape);


            */

            g.DrawLine(Pens.White, centerPoint.X, centerPoint.Y - radius + 5, centerPoint.X - 5, centerPoint.Y - radius + 10);
            g.DrawLine(Pens.White, centerPoint.X - 5, centerPoint.Y - radius + 10, centerPoint.X + 5, centerPoint.Y - radius + 10);
            g.DrawLine(Pens.White, centerPoint.X + 5, centerPoint.Y - radius + 10, centerPoint.X, centerPoint.Y - radius + 5);
 
            // Draw the triangle in the lower position
            g.DrawLine(Pens.White, centerPoint.X, centerPoint.Y + radius - 5, centerPoint.X - 5, centerPoint.Y + radius - 15);
            g.DrawLine(Pens.White, centerPoint.X - 5, centerPoint.Y + radius - 15, centerPoint.X + 5, centerPoint.Y + radius - 15);
            g.DrawLine(Pens.White, centerPoint.X + 5, centerPoint.Y + radius - 15, centerPoint.X, centerPoint.Y + radius - 5);
            
            /*
            if (reset)
            {
                at = AffineTransform.getRotateInstance(Math.toRadians(-180), centerPoint.getX(), centerPoint.getY());
                g2d.transform(at);
            }
             */

            

            g2.DrawImage(buffer,0,0);


            p = new Pen(Color.White, 1.5F);
            for (int i = 0; i <= 90; i += 5)
            {
                at = new Matrix();
                at.RotateAt(-45 + i, new PointF(centerPoint.X + base.margin + margin, centerPoint.Y + base.margin+margin));
                at.Translate(base.margin+margin, base.margin+margin);
                g2.Transform = at;

                if (i % 10 != 0)
                    g2.DrawLine(p, centerPoint.X, centerPoint.Y - radius - 6, centerPoint.X, centerPoint.Y - radius);
                else
                    g2.DrawLine(p, centerPoint.X, centerPoint.Y - radius - 3, centerPoint.X, centerPoint.Y - radius);
            }
            p = new Pen(Color.White, 2);
            g2.DrawEllipse(p, 0, 0, radius * 2, radius * 2);
        }
    }
}
